const Path = require('path');
const join = Path.join;
const fs = require('fs');
const readFileSync = fs.readFileSync;
const parser = require('heapsnapshot-parser');

const { dialog } = require('electron').remote;
const fileContent = readFileSync(join(__filename, "../../package.json"))
const PackageJSON = JSON.parse(fileContent.toString());
const PACKAGE_NAME = PackageJSON.name;
const PACKAGE_PATH = Editor.url(`packages://${PACKAGE_NAME}/`);
const DIR_PATH = join(PACKAGE_PATH, 'panel/');


function loadCSS(files) {
  let css = ""
  for (const file of files) {
    css += readFileSync(file, 'utf-8')
  }

  return css
}

function findNodeByProperty(node, property) {
  for (let i = 0; i < node.references.length; i++) {
    let ref = node.references[i];
    if (ref.type === "property" && ref.name == property) {
      return ref.toNode;
    }
  }
  return null;
}

// 创建面板
Editor.Panel.extend({
  /** HTML */
  style: loadCSS([join(DIR_PATH, 'index.css')]),
  template: readFileSync(join(DIR_PATH, 'index.html'), 'utf8'),
  $: {
    targetFile: "#targetFile",
    progress: "#progress",
    filter: "#filter",
    targetFile: "#targetFile"
    // typeFilter: "#typeFilter",
  },
  ready() {
    let self = this;

    let delayTime = 0.5;
    let timeoutTag = 0;

    let targetFile = "";
    let assets = [];
    let progress = 0;
    let targetFileType = "all";
    let filter = "";
    let finalFiles = [];
    let isParsing = false;

    const typeOptions = [
      { type: "All", selected: true },
      { type: "Texture", selected: false },
      { type: "SpriteFrame", selected: false },
      { type: "Prefab", selected: false },
      { type: "Audio", selected: false },
      { type: "JsonAsset", selected: false },
      { type: "TextAsset", selected: false },
      { type: "Buffer", selected: false },
      { type: "Particle", selected: false },
      { type: "Material", selected: false },
      { type: "Animation", selected: false },
      { type: "Font", selected: false },
      { type: "Effect", selected: false },
      { type: "Skeleton", selected: false },
      { type: "Scene", selected: false },
    ];

    this.plugin = new window.Vue({
      el: this.shadowRoot,
      data() {
        return {
          targetFile,
          progress,
          typeOptions,
          filter,
          finalFiles
        }
      },
      methods: {
        onInputFoucs() {
          dialog.showOpenDialog({ properties: ['openFile'], defaultPath: targetFile, filters: [{ name: 'HeapSnapshot', extensions: ['heapsnapshot'] }] }).then(async result => {
            console.log(result)
            let fontPath = result.filePaths;
            if (fontPath[0]) {
              targetFile = fontPath[0];
              self.$targetFile.value = targetFile;
            }
          }).catch(err => {
            Editor.log(err)
          })
        },

        async onCheckClick() {
          if (!targetFile) {
            Editor.warn('Please select a file first!');
            return;
          }

          if (isParsing) {
            return
          }
          isParsing = true;

          self.$progress.value = 0;
          assets = [];

          let snapshotFile = fs.readFileSync(targetFile, { encoding: "utf-8" });
          self.$progress.value = 5;
          setTimeout(() => {
            let snapshot = parser.parse(snapshotFile);
            this.parseFileFinish(snapshot);
          }, 1000);
        },

        async parseFileFinish(snapshot) {
          let nodes = [];
          let len = snapshot.nodes.length
          for (let i = 0; i < len; i++) {
            self.$progress.value = (i / len) * 5 + 5;
            let node = snapshot.nodes[i];
            if (node.type === "object") {
              // 查找cc对象
              if (node.name === "Object") {
                nodes.push(node);
              }
            }
          }
          nodes = nodes.sort(function (a, b) {
            return b.self_size - a.self_size;
          });

          let nodeToEdges = {};
          let edgesLen = snapshot.edges.length;
          for (let i = 0; i < edgesLen; i++) {
            self.$progress.value = (i / edgesLen) * 30 + 5;
            let edge = snapshot.edges[i];
            if (!edge.toNode || edge.type == "weak" || edge.type == "shortcut") {
              continue;
            }
            if (!nodeToEdges[edge.toNode.id]) {
              nodeToEdges[edge.toNode.id] = [];
            }
            nodeToEdges[edge.toNode.id].push(edge);
          }

          let assetIds = {};
          let nodeslen = nodes.length;
          for (let i = 0; i < nodeslen; i++) {
            let node = nodes[i];
            let assetManagerNode = findNodeByProperty(node, "assetManager");
            if (assetManagerNode) {
              let assetNode = findNodeByProperty(assetManagerNode, "assets");
              if (assetNode) {
                let assetMap = findNodeByProperty(assetNode, "_map");
                if (assetMap) {
                  let allAssetsNode = assetMap.references;
                  allAssetsNode.forEach(element => {
                    assetIds[element.name] = assetNode;
                  });
                }
              }
            }
            self.$progress.value = (i / nodeslen) * 30 + 35;
          }

          let assetIdsArr = Object.keys(assetIds);
          let assetIdsArrLen = assetIdsArr.length;
          let dts = [];
          let finishCount = 0;
          for (let i = 0; i < assetIdsArrLen; i++) {
            let dt = new Promise((resolve, reject) => {
              Editor.assetdb.queryInfoByUuid(assetIdsArr[i], function (err, info) {
                finishCount++;
                self.$progress.value = (finishCount / assetIdsArrLen) * 30 + 70;
                if (info) {
                  assets.push({
                    name: info.displayName || info.name,
                    uuid: info.uuid,
                    file: info.path,
                    type: info.type,
                    baseName: Path.basename(info.path)
                  });
                }
                resolve();
              });
            });
            dts.push(dt);
          }
          await Promise.all(dts);
          this.finalFiles = this.filterFiles();
          isParsing = false;
        },

        onTabChanged(clickedOption) {
          this.typeOptions.forEach((option) => {
            option.selected = option === clickedOption;
          });
          targetFileType = clickedOption.type.toLowerCase();
          this.finalFiles = this.filterFiles();
        },

        inputChange() {
          clearTimeout(this.timeoutTag);
          this.timeoutTag = setTimeout(() => {
            this.finalFiles = this.filterFiles();
            clearTimeout(this.timeoutTag);
          }, this.delayTime * 1000);
        },

        filterFiles() {
          if (self.$filter.value == "" && targetFileType == "all") {
            return assets;
          }

          let fileName = self.$filter.value.toLowerCase();
          let type = targetFileType.toLowerCase();
          return assets.filter((item) => {
            if (type != "all" && item.type.toLowerCase().indexOf(type) < 0) {
              return false;
            }
            return (item.name && item.name.toLowerCase().indexOf(fileName) >= 0) || (item.uuid && item.uuid.toLowerCase().indexOf(fileName) >= 0) || (item.file && item.file.toLowerCase().indexOf(fileName) >= 0)
          });
        },

        onAssetClick(data) {
          Editor.Ipc.sendToAll("assets:hint", data.uuid);
        }
      }
    })
  }
});
